package cn.thornbird.orgsync.model;

import cn.thornbird.orgsync.entity.User;
import cn.thornbird.orgsync.entity.status.UserType;
import cn.thornbird.orgsync.exception.ForbiddenException;
import cn.thornbird.orgsync.util.JsonUtil;
import lombok.Data;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

@Data
public class UserData implements UserDetails {

    public static final String ADMIN = "admin";

    public static final String AUTHORIZED = "authorized";

    public static final String NORMAL = "normal";

    private static final long serialVersionUID = 8722033359966214889L;

    private String id;

    private String avatar;

    private String username;

    private String password;

    private boolean accountNonExpired;

    private boolean accountNonLocked;

    private boolean credentialsNonExpired;

    private boolean enabled;

    private boolean superuser;

    private boolean needChangePassword;

    private String authorizedOpinions;

    private Collection<Resource> authorities;

    public UserData(User user, List<Resource> resources) {
        Date now = new Date();
        id = user.getId();
        avatar = user.getAvatar();
        username = user.getUsername();
        password = user.getPassword();
        accountNonExpired = true;
        accountNonLocked = true;
        credentialsNonExpired = true;
        enabled = false;
        superuser = false;
        needChangePassword = false;
        authorizedOpinions = user.getAuthorizedOpinions();
        authorities = new ArrayList<>();
        if (user.getEffectiveDate() != null && user.getEffectiveDate().compareTo(now) > 0) {
            accountNonExpired = false;
        }
        if (user.getTerminateDate() != null && user.getTerminateDate().compareTo(now) < 0) {
            accountNonExpired = false;
        }
        if (user.getLocked() != null && user.getLocked()) {
            accountNonLocked = false;
        }
        if (user.getActive() != null && user.getActive()) {
            enabled = true;
        }
        if (user.getSuperuser() != null && user.getSuperuser()) {
            superuser = true;
        }
        if (user.getPasswordTerminateDate() != null) {
            if (user.getPasswordTerminateDate().compareTo(now) < 0) {
                needChangePassword = true;
            }
        }
        if (user.getNeedChangePassword() != null && user.getNeedChangePassword()) {
            needChangePassword = true;
        }
        if (resources != null) {
            this.getAuthorities().addAll(resources);
        }
        if (user.getSuperuser() != null && user.getSuperuser().booleanValue()) {
            getAuthorities().add(new Resource(ADMIN));
        }
        if (user.getType() != null && user.getType().equals(UserType.Authorized)) {
            getAuthorities().add(new Resource(AUTHORIZED));
        }
        if (user.getType() != null && user.getType().equals(UserType.Normal)) {
            getAuthorities().add(new Resource(NORMAL));
        }
    }

    @Override
    public Collection<Resource> getAuthorities() {
        return authorities;
    }

    @Override
    public boolean equals(Object object) {
        if (object != null && JsonUtil.toJsonString(this).equals(JsonUtil.toJsonString(object))) {
            return true;
        }
        return false;
    }

    public void checkAuthority(String resourceCode) throws ForbiddenException {
        if (!hasAuthority(resourceCode)) {
            throw new ForbiddenException(String.format("禁止操作，没有%s权限", resourceCode));
        }
    }

    public boolean hasAuthority(String resourceCode) {
        if (superuser) {
            return true;
        }
        boolean flag = false;
        if (authorities != null && !authorities.isEmpty()) {
            for (Resource resource : authorities) {
                if (resource.getAuthority().equals(resourceCode)) {
                    flag = true;
                    break;
                }
            }
        }
        return flag;
    }

}
